#pragma once 


#include <jsoncpp/json/reader.h>
#include <jsoncpp/json/value.h>
#include <jsoncpp/json/writer.h>
#include <log.h>
#include <memory>
#include <vector>
#include <jsoncpp/json/json.h>

#include "http.h"

namespace lyt {

    static std::string serializer(const Json::Value& root) {
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> write(swb.newStreamWriter());
        std::stringstream ss;
        if(write->write(root, &ss) != 0){
            return "";
        }
        return ss.str();
    }
    static bool deserializer(const std::string& body,Json::Value* root) {
        Json::CharReaderBuilder crb;
        std::unique_ptr<Json::CharReader> read(crb.newCharReader());
        return read->parse(body.data(), body.data() + body.size(), root, nullptr);
    }

    class esclient{
    public:
        using ptr = std::shared_ptr<esclient>;

        esclient(const std::vector<std::string>& hosts) 
            :_hosts(hosts),
            _requestor(std::make_shared<http::http>())
        {}
        ~esclient() {}

        // 创建索引
        bool index(const std::string& index_name, const std::string& body) {
            std::string path = std::string("/") + index_name;
            auto result = _requestor->make_request(http::get, gethost(), path);
            if (result.first){
                return true;
            }
            result = _requestor->make_request(http::put, gethost(), path, body);
            return result.first;
        }
        // 删除索引
        bool remove_index(const std::string& index_name){
            std::string path = std::string("/") + index_name;
            auto result = _requestor->make_request(http::delete_, gethost(), path);
            return result.first;
        }
        // 插入数据
        bool insert(const std::string& index_name, const std::string& id, const std::string& body) {
            std::string path = std::string("/") + index_name + "/_doc/" + id;
            auto result = _requestor->make_request(http::post, gethost(), path,body);
            return result.first;
        }
        // 删除数据
        bool remove_data(const std::string& index_name, const std::string& id) {
            std::string path = std::string("/") + index_name + "/_doc/" + id;
            auto result = _requestor->make_request(http::delete_, gethost(), path);
            return result.first;
        }
        // 搜索数据
        std::string search(const std::string& index_name, const std::string& body) {
            std::string path = std::string("/") + index_name + "/_doc/_search?pretty";
            auto result = _requestor->make_request(http::post, gethost(), path, body);
            return result.second;
        }

    private:
        std::string gethost() {
            static thread_local int _index = 0;
            _index = (_index + 1) % _hosts.size();
            return _hosts[_index];
        }

    private:
        http::http::ptr _requestor;
        std::vector<std::string> _hosts;
    };

    /**
    PUT /user
    { 
        "settings" : { 
            "analysis" : { 
                "analyzer" : {  
                    "ik" : { 
                        "tokenizer" : "ik_max_word" 
                    } 
                } 
            } 
        },
        "mappings" : { 
            "dynamic" : true, 
            "properties" : { 
                "nickname" : {
                    "type" : "text", 
                    "analyzer" : "ik_max_word" ,
                    "fields": {
                        "keyword" : {
                            "type" : "keyword"
                        }
                    }
                },
                "user_id" : {
                    "type" : "keyword"
                },
                "phone" : {
                    "type" : "keyword"
                }
            } 
        }
    }
    */
    class index{
    public:
        using ptr = std::shared_ptr<index>;
        index(const esclient::ptr& client):_client(client) {
            _root["settings"]["analysis"]["analyzer"]["ik"]["tokenizer"] = "ik_max_word";
            _root["mappings"]["dynamic"] = true;
        }

        index& add_text_field(const std::string& name) {
            _root["mappings"]["properties"][name]["type"] = "text";
            _root["mappings"]["properties"][name]["analyzer"] = "ik_max_word";
            _root["mappings"]["properties"][name]["fields"]["keyword"]["type"] = "keyword";
            return *this;
        }
        index& add_date_field(const std::string& name,
            const std::string& format = "yyyy-MM-dd HH:mm:ss||strict_date_optional_time||epoch_millis"){
            _root["mappings"]["properties"][name]["type"] = "date";
            _root["mappings"]["properties"][name]["format"] = format;
            return *this;
        }
        index& add_keyword_field(const std::string& name) {
            _root["mappings"]["properties"][name]["type"] = "keyword";
            return *this;
        }
        index& add_integer_field(const std::string& name) {
            _root["mappings"]["properties"][name]["type"] = "integer";
            return *this;
        }
        index& add_dense_vector_384_field(const std::string& name) {
            _root["mappings"]["properties"][name]["type"] = "dense_vector";
            _root["mappings"]["properties"][name]["dims"] = 384;
            _root["mappings"]["properties"][name]["index"] = true;
            _root["mappings"]["properties"][name]["similarity"] = true;
            _root["mappings"]["properties"][name]["index_options"]["type"] = "hnsw";
            _root["mappings"]["properties"][name]["index_options"]["m"] = 16;
            _root["mappings"]["properties"][name]["index_options"]["ef_construction"] = 100;
            return *this;
        }

        bool run(const std::string& index_name) {
            return _client->index(index_name, serializer(_root));
        }

    private:
        esclient::ptr _client;
        Json::Value _root;
    };

    /**
     
    POST /user/_doc/2
    {
        "user_id" : "USER14eeeaa5-442771b9-0262e455-e4663d1d",
        "nickname" : "免费好用的满血版 DeepSeek，支持深度思考和联网搜索，免费不限次数，网络不卡顿",
        "phone" : "手机号 2"
    }

    ***/
    class insert {
    public:
        using ptr = std::shared_ptr<insert>;
        insert(const esclient::ptr& client):_client(client){}
        // string 类型
        insert& set_value(const std::string& key, const std::string& value){
            _root[key] = value;
            return *this;
        }
        // int 类型
        insert& set_value(const std::string& key, int value) {
            _root[key] = value;
            return *this;
        }
        // vector 类型
        insert& set_value(const std::string& key, std::vector<double> value) {
            for(auto& d : value){
                _root[key].append(d);
            }
            return *this;
        }

        // unsigned long long 类型
        insert& set_value(const std::string& key, unsigned long long value) {
            _root[key] = Json::UInt64(value);
            return *this;
        }

        bool run(const std::string& index_name,const std::string& id) {
            return _client->insert(index_name, id, serializer(_root));
        }
        
    private:
        esclient::ptr _client;
        Json::Value _root;
    };
    
    
    /*


    # 查询数据
    GET /user/_doc/_search?pretty
    { 
        "query" : { 
            "bool" : { 
                "must_not" : [ 
                    { 
                        "terms" : { 
                            "user_id" : [ 
                                "USER4b862aaa-2df8654a-7eb4bb65-e3507f66"
                            ] 
                        } 
                    } 
                ],
                "should" : [ 
                    { 
                        "match" : {
                            "user_id" : "昵称" 
                        } 
                    },
                    { 
                        "match" : {
                            "nickname" : "昵称" 
                        } 
                    },
                    { 
                        "match" : {
                            "phone" : "昵称" 
                        } 
                    } 
                ]
            } 
        } 
    }


    GET /user/_doc/_search?pretty
    { 
        "query" : { 
            "bool" : { 
                "should" : [ 
                    {
                    "match" : {
                        "nickname" : "DeepSeek" 
                    }
                    }
                ] 
            } 
        } 
    }
     */

    class search{
    public:
        using ptr = std::shared_ptr<search>;
        search(const esclient::ptr& client):_client(client) {}
        // ================ should ==================
        search& add_should_match(const std::string& key, const std::string& value) {
            Json::Value match;
            match["match"][key] = value;
            _root["query"]["bool"]["should"].append(match);
            return *this;
        }
        // 字段的类型是text
        search& add_should_terms_text(const std::string& key, const std::vector<std::string>& values) {
            Json::Value match;
            for (auto value : values) {
                match["terms"][key + ".keyword"].append(value);
            }
            _root["query"]["bool"]["should"].append(match);
            return *this;
        }
        // 字段的类型是keyword
        search& add_should_terms_keyword(const std::string& key, const std::vector<std::string>& values) {
            Json::Value terms;
            for (auto value : values) {
                terms["terms"][key].append(value);
            }
            _root["query"]["bool"]["should"].append(terms);
            return *this;
        }
        // ================ must_not ==================
        search& add_must_not_match(const std::string& key, const std::string& value) {
            Json::Value match;
            match["match"][key] = value;
            _root["query"]["bool"]["must_not"].append(match);
            return *this;
        }
        // 字段的类型是text
        search& add_must_not_terms_text(const std::string& key, const std::vector<std::string>& values) {
            Json::Value match;
            for (auto value : values) {
                match["terms"][key + ".keyword"].append(value);
            }
            _root["query"]["bool"]["must_not"].append(match);
            return *this;
        }
        // 字段的类型是keyword
        search& add_must_not_keyword(const std::string& key, const std::vector<std::string>& values) {
            Json::Value terms;
            for (auto value : values) {
                terms["terms"][key].append(value);
            }
            _root["query"]["bool"]["must_not"].append(terms);
            return *this;
        }

        // ================ must ==================
        search& add_must_match(const std::string& key, const std::string& value) {
            Json::Value match;
            match["match"][key] = value;
            _root["query"]["bool"]["must"].append(match);
            return *this;
        }
        // 字段的类型是text

        search& add_must_terms_text(const std::string& key, const std::vector<std::string>& values) {
            Json::Value match;
            for (auto value : values) {
                match["terms"][key + ".keyword"].append(value);
            }
            _root["query"]["bool"]["must"].append(match);
            return *this;
        }
        // 字段类型是integer
        search& add_must_terms_integer(const std::string& key, const std::vector<uint32_t>& values) {
            Json::Value term_vals;
            for (auto val : values) {
                term_vals["terms"][key].append(val);  // 直接添加 integer，不用 .keyword
            }
            _root["query"]["bool"]["must"].append(term_vals);
            return *this;
        }

        // 字段的类型是keyword
        search& add_must_keyword(const std::string& key, const std::vector<std::string>& values) {
            Json::Value terms;
            for (auto value : values) {
                terms["terms"][key].append(value);
            }
            _root["query"]["bool"]["must"].append(terms);
            return *this;
        }
        // 添加from和size参数使支持分页搜索
        search& set_from(int from) {
            _root["from"] = from;
            return *this;
        }
        search& set_size(int size) {
            _root["size"] = size;
            return *this;
        }
        // 添加sort使支持排序
        search& add_sort(const std::string& field, bool asc = true) {
            Json::Value sort_field;
            sort_field[field]["order"] = asc ? "asc" : "desc";
            _root["sort"].append(sort_field);
            return *this;
        }
        // 指定返回的结果中不包含的字段
        search& exclude_field(const std::string& field) {
            _root["_source"]["excludes"] = field;
            return *this;
        }
        search& vector_search(const std::vector<double>& vector_data,const std::string& feild) {
            _root["query"]["script_score"]["query"]["match_all"] = Json::objectValue;
            _root["query"]["script_score"]["script"]["source"] = std::string("cosineSimilarity(params.queryVector, '") + feild + "') + 1.0";
            for (auto& d : vector_data){
                _root["query"]["script_score"]["script"]["params"]["queryVector"].append(d);
            }
            return *this;
        }

        /*  这里返回的应该是一个json的数组
        [
            {
                "_index" : "user",
                "_type" : "_doc",
                "_id" : "2",
                "_score" : 1.0,
                "_source" : {
                    "key" : "value",
                }
            },
            ...
        ]
        */
        std::pair<Json::Value,int> run(const std::string& index_name) {
            std::string result_str =  _client->search(index_name, serializer(_root));
            Json::Value result;
            deserializer(result_str, &result);
            return std::make_pair(result["hits"]["hits"],result["hits"]["total"]["value"].asInt());
        }

    private:
        esclient::ptr _client;
        Json::Value _root;
    };

    class remove{
    public:
        remove(esclient::ptr client):_client(client){}
        
        bool run(const std::string& index, const std::string& id) {
            return _client->remove_data(index, id);
        }
        ~remove(){}
        
    private:
        esclient::ptr _client;
        Json::Value _root;
    };

}
